//  Copyright (c) 2017 Hartmut Kaiser
//  Copyright (c) 2015-2016 Anton Bikineev
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <hpx/runtime/serialization/serialize.hpp>
#include <hpx/runtime/serialization/string.hpp>
#include <hpx/runtime/serialization/vector.hpp>
#include <hpx/version.hpp>

#include <chrono>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include <boost/lexical_cast.hpp>

std::size_t const kStringsCount = 100;
std::string const kStringValue =
    "shgfkghsdfjhgsfjhfgjhfgjsffghgsfdhgsfdfkdjh"
    "fioukjhkfdljgdfkgvjafdhasgdfwurtjkghfsdjkfg";

std::vector<std::int64_t> const kIntegers =
{
    34492,6603,44033,8874,47607,38416,20395,29192,38620,36775,
    35058,20501,39664,64574,11261,35679,16607,26020,39476,16699,
    21505,20947,53587,24746,45980,18827,137,61753,53340,25406,
    31601,38267,47951,62073,6738,42983,19246,34384,51818,157,
    628,40807,41177,49445,60677,23663,22312,20616,28922,20389,
    28543,48407,63986,7216,61601,6647,7956,47434,29257,28162,
    25582,29941,55019,60580,47503,6662,35851,23648,61464,43188,
    23519,37727,36778,62597,27203,31950,23796,62866,54914,4507,
    7775,39256,56141,36388,58687,42619,30909,47784,44209,38712,
    39387,37342,36743,17467,21181,36301,3918,10068,16204,50558,
    33633,6164,111,30859,56608,3320,17784,17842,3623,9258,
    38514,46795,60113,5658,38229,16986,64707,17010,35380,34811,
    13179,21861,23487,27513,18226,29112,41034,57128,27903,5484,
    64117,27389,45096,15321,42035,30690,13359,20005,35723,52158,
    29700,2895,46899,54388,50709,44269,11880,43493,46848,47523,
    64268,11074,673,62425,10609,21895,65353,51268,30048,8327,
    15020,13098,8614,9162,44230,34945,49663,35106,37002,13147,
    23661,47571,58767,27158,58907,18884,29017,49330,21161,20261,
    22381,57315,11034,39237,35876,52748,52135,3652,5573,11120,
    35955,16213,32062,32349,26362,7882,39528,40116,378,3620,
    23121,39308,39836,55477,12003,34089,54450,23870,1952,58445,
    38567,53959,32265,10354,57972,31510,264,44462,61043,48989,
    59504,34995,21591,56088,47298,64849,51629,64161,30990,34752,
    28699,58836,28310,27686,53360,58218,1382,12294,17239,24411,
    50012,11485,2732,43364,34433,12782,23748,25393,49417,19316,
    56304,54887,48832,4473,31997,8192,14593,32054,54448,60709,
    26749,18928,53574,8031,23681,61479,32115,48730,15694,51143,
    37232,25059,11327,31269,18035,24905,30575,35576,50878,63566,
    7213,10140,13121,13487,53861,3487,58552,11636,42412,59239,
    38086,16738,16197,45757,47844,18248,14385,64858,2785,43969,
    55873,34166,42623,15441,55015,9219,47800,3659,47139,54900,
    36120,23551,51858,64110,44719,51319,17756,56240,44986,22746,
    4944,50980,43252,4881,53006,12039,41658,49870,54730,10213,
    15296,9139,54583,7345,10260,58177,4126,46487,15644,1323,
    7767,40475,61334,33814,296,4202,58954,60710,47287,17842,
    62948,40443,16982,64708,45849,58300,16400,20536,38687,3543,
    14340,17591,37874,58282,12109,61025,17392,4014,39117,40912,
    24572,39998,57703,4373,28314,27751,11307,43386,28218,4223,
    10843,46516,48966,472,54111,55663,33428,52509,3845,5647,
    3164,36542,16868,5700,44693,1240,12757,22308,12715,9024,
    11999,42661,57211,50848,14944,59955,59208,41264,20033,23019,
    6368,43478,48738,14758,41280,24076,64014,52013,24937,46899,
    59046,52457,22428,27505,43159,17779,26304,23403,52731,32394,
    11878,6003,29789,43818,59314,20329,58069,13081,61424,27718,
    29996,21610,3205,14477,37523,35003,36286,62906,44191,31058,
    53068,826,49309,1705,44214,29908,19433,61948,46663,42710,
    15534,7807,36492,51075,56749,56906,28946,10316,12099,38561,
    41455,12573,42613,18640,64463,61175,61712,57225,10181,60007,
    49094,30559,59477,48603,15646,56068,58417,29704,40969,37530,
    18769,35771,62828,64452,43719,35415,9679,48100,37102,2014,
    37901,40564,5231,35279,31257,46681,36297,49026,30314,53309,
    1772,15145,34777,28019,28568,11004,55343,63726,32528,7595,
    7288,61637,55329,11723,41610,36885,34524,9144,58781,31381,
    31576,51243,65449,3883,24602,41301,49332,30071,24731,53076,
    18835,30948,31196,15758,58879,8007,16244,56729,31879,13324,
    30246,59487,40604,41656,9922,16564,41094,26477,14418,47704,
    46087,43602,35364,3468,28154,40737,22138,29789,22868,29611,
    137,18409,26366,11641,24154,33214,53316,54678,56564,6485,
    63859,30593,23819,63569,40255,28125,3821,58358,26034,27326,
    20168,39097,34762,3861,54465,48588,41685,9521,42716,60424,
    61811,64517,55711,28716,5876,16802,43184,32158,12460,33802,
    43630,57941,65454,57092,23134,1757,42449,56716,47808,31003,
    52358,59607,60476,14763,48276,61767,52541,15148,59109,60993,
    8607,56930,13760,52036,4132,61711,4915,59651,11062,750,
    32426,26748,61727,1006,38136,15828,5934,5901,37067,46827,
    11884,17393,6322,58799,45596,60370,61443,46045,64246,48987,
    2765,29446,10923,21875,48410,39056,42986,5562,17903,63126,
    57165,16031,63190,41857,20363,25337,60583,34165,12117,31144,
    15233,32201,50866,19101,22325,45683,41215,28885,42919,56843,
    26045,18702,32409,4802,11310,50435,18268,34070,56862,48307,
    27179,35722,23159,5270,62523,55928,37842,1469,52744,63149,
    61265,28590,10318,36834,31225,55332,26967,34844,53898,13550,
    45088,18743,10663,64974,29124,42159,34634,3895,22055,5649,
    53895,30439,38264,18351,980,62663,5479,32694,2392,14157,
    34319,34875,42709,52995,35927,63947,62191,63907,24903,15705,
    40955,50782,64934,62454,19404,53365,25945,57405,41221,12921,
    34291,15944,32298,4083,30010,44032,41316,28130,31221,18940,
    44513,5513,24837,54233,9899,39933,29068,23247,47440,52698,
    63372,8945,51493,57120,52514,20487,60260,59814,1484,24789,
    33866,45112,14526,60221,50973,25125,5991,48481,33017,59821,
    42654,51735,63141,55833,14490,35443,44171,62286,36815,23160,
    32977,31387,20525,49812,1295,43744,18217,34480,58203,61045,
    25528,48777,55709,47339,37999,49039,45022,35884,33880,44348,
    1526,6778,14068,16467,699,3820,2828,55811,62784,22958,
    21898,18678,15946,42931,47002,933,19312,32862,25994,6791,
    58533,15443,21048,11212,28899,9618,9053,61352,45516,23407,
    35256,58880,36406,36544,6981,30273,65302,37871,10065,19591,
    6464,15831,40594,62620,61300,39313,57367,56539,21501,61070,
    13632,27764,60371,47978,38670,33853,31205,49260,56140,18928,
    27245,47480,45291,64421,19547,29616,38608,45751,62137,18789,
    59923,25449,57664,9889,18109,26588,20278,51672,21209,23202,
    29419,55090,35147,32818,15270,49125,30648,64720,29814,57758,
    25352,11149,3703,16912,60520,34110,42527,1438,36294,17877,
    52345,28849,16183,34088,37493,39997,54697,970,14983,60268,
    19566,32131,54265,10366,49778,1520,43174,34006,64401,58034,
    35005,27621,65337,58940,9671,6424,61857,22542,30725,61777,
    12539,29197,24034,28450,2769,41642,50160,47847,18152,51053,
    47843,61836,25260,36400,22250,17010,29460,51714,42262,28230,
    54088,34531,17424,36588,53806,32847,11804,28344,16504,38941,
    23441,53703,31551,61990,59981,19355,32417,16169,64680,1600
};

namespace hpx_test
{
    typedef std::vector<std::int64_t> Integers;
    typedef std::vector<std::string> Strings;

    class Record
    {
    public:
        Integers ids;
        Strings strings;

        bool operator==(const Record &other)
        {
            return (ids == other.ids && strings == other.strings);
        }

        bool operator!=(const Record &other)
        {
            return !(*this == other);
        }

    private:
        friend class hpx::serialization::access;

        template <typename Archive>
        void serialize(Archive &ar, unsigned int)
        {
            ar & ids;
            ar & strings;
        }
    };

    void to_string(const Record &record, std::string& data)
    {
        hpx::serialization::output_archive archiver(data);
        archiver << record;
    }

    void from_string(Record &record, std::string const& data)
    {
        hpx::serialization::input_archive archiver(data);
        archiver >> record;
    }
}

void hpx_serialization_test(std::size_t iterations)
{
    using namespace hpx_test;

    Record r1, r2;
    for (std::int64_t kInteger : kIntegers)
    {
        r1.ids.push_back(kInteger);
    }

    for (std::size_t i = 0; i < kStringsCount; i++)
    {
        r1.strings.push_back(kStringValue);
    }

    std::string serialized;
    to_string(r1, serialized);
    from_string(r2, serialized);

    if (r1 != r2)
    {
        throw std::logic_error("hpx's case: deserialization failed");
    }

    std::cout << "hpx: version = " << hpx::full_version_as_string() << std::endl;
    std::cout << "hpx: size    = " << serialized.size() << " bytes" << std::endl;

    auto start = std::chrono::high_resolution_clock::now();

    for (size_t i = 0; i < iterations; ++i)
    {
        serialized.clear();
        to_string(r1, serialized);
        from_string(r2, serialized);
    }

    auto finish = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
        finish - start).count();

    std::cout << "hpx: time    = " << duration << " milliseconds"
              << std::endl << std::endl;
}

int main(int argc, char **argv)
{
    if (argc < 2)
    {
        std::cout << "usage: " << argv[0] << " N";
        std::cout << std::endl << std::endl;
        std::cout << "arguments: " << std::endl;
        std::cout << " N  -- number of iterations" << std::endl << std::endl;
        return 0;
    }

    std::size_t iterations;
    try {
        iterations = boost::lexical_cast<size_t>(argv[1]);
    }
    catch (std::exception &exc) {
        std::cerr << "Error: " << exc.what() << std::endl;
        std::cerr << "First positional argument must be an integer." << std::endl;
        return -1;
    }

    hpx_serialization_test(iterations);
}

